package by.yativem.commons.console;

import org.apache.log4j.Logger;

import by.yativem.commons.console.devices.ITextDevice;
import by.yativem.commons.console.devices.StreamConsoleDevice;
import by.yativem.commons.console.devices.SystemConsoleDevice;
import by.yativem.commons.utils.string.StringUtil;


/**
 * @author Aliaksei_Miadzvedzeu
 *
 */
public class Console extends Thread{
	private static final Logger log = org.apache.log4j.LogManager.getLogger(Console.class);
	private static final String CONSOLE_COMMAND_PREFIX = "c_";
	
	protected static final String CONSOLE_COMMAND_EXIT = CONSOLE_COMMAND_PREFIX +"exit";
	protected static final String CONSOLE__COMMAND_USE = CONSOLE_COMMAND_PREFIX + "use_param";
	protected static final String CONSOLE__COMMAND_CLEAN_USE_PARAM = CONSOLE_COMMAND_PREFIX + "clean_param";
	
	protected  ITextDevice textDevice;
	protected String use ="";
	protected IConsoleLogger consoleLogger  = new IConsoleLogger() {
		
		@Override
		public void consoleOutput(String str) {
			// TODO Auto-generated method stub
			
		}
		
		@Override
		public void consoleInput(String str) {
			// TODO Auto-generated method stub
			
		}
	};
	
	protected IConsoleClient consoleClient;
	
	protected boolean sholdContinue = true;
	
	

	public static ConsoleCommandBean buildCommandBean(String str) {
		ConsoleCommandBean result = new ConsoleCommandBean();
		String delims = "[ ]+";
		String[] tokens = str.split(delims);
		try {
			// get command Name
			int i = 0;
			while (i < tokens.length && "".equals(tokens[i])) {
				i++;
			}

			if (i < tokens.length && !"".equals(tokens[i])) {
				result.commandName = tokens[i];
				i++;
			} else {
				throw new IllegalArgumentException();
			}
			// get arguments
			while (i < tokens.length) {
				if ("".equals(tokens[i])) {
					i++;
					continue;
				} else {
					if (tokens[i].startsWith("--")) {
						String argName = tokens[i].substring(2);
						i++;
						String argVal = tokens[i];
						result.params.put(argName, argVal);
					} else {
						if (tokens[i].startsWith("-")) {
							String argName = tokens[i].substring(1);
							result.params.put(argName, null);
						} else {
							throw new IllegalArgumentException();
						}
					}
				}
				i++;
			}

		} catch (Exception e) {
			throw new IllegalArgumentException("Invalid argument passed: " + str, e);
		}
		return result;
	}

	public Console(ITextDevice textDevice ){
		this.textDevice = textDevice;
	}	
	
	public Console(){
		this.setName("Console");
		if(System.console() != null){
			textDevice = new SystemConsoleDevice();
		}else{
			textDevice = new StreamConsoleDevice(System.in, System.out);
		}
	}

	public void run() {

		while (sholdContinue) {
			try {
				if(! StringUtil.isBlank(use)){
					write(use);
				}				
				write(">");
				
				String inStr = readLine();
				if(! StringUtil.isBlank(inStr)){
					inStr = inStr + " " + use;
					writeLine("passed :" + inStr);
				}
				ConsoleCommandBean commandBean = buildCommandBean(inStr);
				
				if( ! processConsoleCommand(commandBean)){
					Object result = consoleClient.sendCommand(commandBean);
					
					writeLine(result.toString());
				}
				
				
			} catch (Exception e) {
				log.error(e);
				writeLine(e.getMessage());

			}
		}

	}

	
	public ITextDevice getTextDevice() {
		return textDevice;
	}

	public void setTextDevice(ITextDevice iTextDevice) {
		this.textDevice = iTextDevice;
	}

	public IConsoleLogger getConsoleLogger() {
		return consoleLogger;
	}

	public void setConsoleLogger(IConsoleLogger consoleLogger) {
		this.consoleLogger = consoleLogger;
	}

	public IConsoleClient getConsoleClient() {
		return consoleClient;
	}

	public void setConsoleClient(IConsoleClient consoleClient) {
		this.consoleClient = consoleClient;
	}
	
	/**
	 * @param commandBean
	 * @return Return true if the commandBean is represent a console command.
	 * 
	 *  Check The command and process it if the command is "Console command". Like 'exit'.
	 */
	protected boolean processConsoleCommand(ConsoleCommandBean commandBean){
		boolean result = false;
		if(CONSOLE_COMMAND_EXIT.equals(commandBean.getCommandName() )){
			sholdContinue = false;
			result =  true;
		}	
		
		if(CONSOLE__COMMAND_USE.equals(commandBean.getCommandName())){
			StringBuilder sb = new StringBuilder();
			for(String param : commandBean.getParams().values() ){
				sb.append(" ").append(param);
				if(null != commandBean.getParam(param)){
					sb.append(" --").append(commandBean.getParam(param));
				}
			}			
			this.use = sb.toString();
			result =  true;
		}
		
		if(CONSOLE__COMMAND_CLEAN_USE_PARAM.equals(commandBean.getCommandName())){
			this.use = "";
			result = true;
		}
		return result;
	}
	
	
	protected String readPsswrd(){
		char[] psswrd = textDevice.readPassword();
		String tmp =  String.valueOf(psswrd);
		consoleLogger.consoleInput(tmp);
		return tmp;
	}	
	
	protected String readLine(){
		String tmp = textDevice.readLine();
		consoleLogger.consoleInput(tmp);
		return tmp;
	}
	
	protected void write(String str){
		consoleLogger.consoleOutput(str);
		textDevice.write(str);
	}
	
	protected void writeLine(String str){
		consoleLogger.consoleOutput(str);
		textDevice.write(str + "\n");
	}

}
